package functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.parsers;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.collections.FastHashMap;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.Gene;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.GeneLibrary;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.SemanticSimilarity;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.utils.FileUtils;

/**
 * Parses a file of semantic similarities, as output by the "distances" program of this application.
 * The file being parsed should firstly contain a the tag "#genes" followed by a list of annotated gene IDs, one per line.
 * The file should then contain the tag "#non-zero similarities", followed by a list of semantic similarities
 * between two genes in the format:
 *
 * <p>geneID_1 \t geneID_2 \t semanticSimilarity</p>
 *
 * The semanticSimilarity should be an integer value.
 * 
 * @author jamie
 */
public class SimilarityFileParser {

    // stores the list of annotated genes
    private List<Gene> allAnnotatedGenes = new ArrayList<Gene>();

    // stores the semantic similarities, key is a hashCode, value is a SemanticSimilarity Object.
    private FastHashMap similarityHash;

    // a library of all the genes
    private GeneLibrary library = new GeneLibrary();


    /**
     * The <code>GeneLibrary</code> that stores a non-redundant list of <code>Gene</code> objects to be used.
     * @return the <code>GeneLibrary</code>
     */
    public GeneLibrary getGeneLibrary() {
        return library;
    }

    /**
     * Given a file, the method will read all semantic similarities in to the similarityHash field.
     * Will throw an exception if there is a problem reading the file.
     * @param similarityFile the file to be read
     * @throws IOException thrown if the file can't be read.
     */
    public void readAllSimilarities(File similarityFile) throws IOException {
        BufferedReader reader = FileUtils.getBufferedReader(similarityFile);
        String line;
        similarityHash = new FastHashMap();
        try {
            addAnnotatedGeneIds(reader);

            addSimilarities(reader);

        } catch (IOException ex) {
            Logger.getLogger(SimilarityFileParser.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            reader.close();
        }



    }

    /**
     * Returns the list of all annotated genes that were read in.
     * @return the list of genes that are annotated.
     */

    public List<Gene> getAnnotatedGenes() {
        return allAnnotatedGenes;
    }

    /**
     * Returns the map of semantic similarities. The key is a hashCode,
     * the value is a <code>SemanticSimilarity</code> object.
     * @return the map of similarities.
     */
    public FastHashMap getSimilarityHash() {
        return similarityHash;
    }

    /**
     * Given a buffered reader, the method will read in gene IDs until it hits the tag "#non-zero similarities".
     * The program will exit if there are no annotated genes found.
     * @param reader the <code>BufferedReader</code> that is reading the input file.
     * @throws IOException id there is a problem reading the file.
     */
    private void addAnnotatedGeneIds(BufferedReader reader) throws IOException {
        String line;

        while ((line = reader.readLine()) != null) {
            if (line.startsWith("#non-zero similarities")) {
                break;
            } else if (!line.startsWith("#genes")) {
                allAnnotatedGenes.add(library.getGene(line));
            }
        }
        if (allAnnotatedGenes.size() == 0) {
            System.out.println("there is no annotated gene list in this file");
            System.out.println("exiting program");
            System.exit(0);
        }


    }

    /**
     * Given a buffered reader, the method will read in sematic similarity data until it hits the end of the file.
     * The program will exit if there are no semantic similarities genes found.
     * @param reader the <code>BufferedReader</code> that is reading the input file.
     * @throws IOException id there is a problem reading the file.
     */
    private void addSimilarities(BufferedReader reader) throws IOException {
        String line;
        while ((line = reader.readLine()) != null) {
            String split[] = line.split("\t");
            try{
                SemanticSimilarity sim = new SemanticSimilarity(library.getGene(split[0]), library.getGene(split[1]));
                sim.setSimilarity(Integer.parseInt(split[2]));
                similarityHash.put(sim.hashCode(), sim);
            } catch(ArrayIndexOutOfBoundsException exception){
                System.out.println("a line in the similarity file does not have the correct structure, line is:");
                System.out.println(line);
                System.out.println(" -- skipping this line");
            } catch(NumberFormatException exception){
                System.out.println("a line in the similarity file does not have an integer similarity in the third column, line is:");
                System.out.println(line);
                System.out.println(" -- skipping this line");
            }
            
        }
        if (similarityHash.size() == 0) {
            System.out.println("there are no semantic similarities given in this file");
            System.out.println("exiting program");
            System.exit(0);
        }


    }
}
